/*
 * ObjectContext.h
 *
 */

/*
 * * * * * * * * * * * * * Template ed Header * * * * * * * * * * * *
 *
 * Anche se si creano definizioni non inline di funzioni, usualmente
 * si vorrà inserire tutte le dichiarazioni e tutte le definizioni
 * per un template in un header file. Questa può apparire come una
 * violazione della normale regola dell’header file “non inserire
 * alcunchè che allochi memoria,” (la quale previene errori di
 * definizioni multiple al momento del linkaggio), ma le definizioni
 * template sono speciali. Qualsiasi cosa preceduta da template<...>
 * significa che il compilatore non allocherà memoria per essa in
 * quel punto, ma aspetterà finchè sia chiamata (da un’istanziazione
 * di template), e che da qualche parte nel compilatore e nel linker
 * c’è un meccanismo per la rimozione di definizioni multiple di un
 * identico template. Così si metteranno quasi sempre nell’header
 * file sia la dichiarazione sia la definizione dell’intero template,
 * per la facilità d’uso.
 *
 * Tratto da "Pensare in C++" seconda edizione, traduzione del libro
 * "Thinking in C++" di Bruce Eckel.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 */

#ifndef OBJECTCONTEXT_H_
#define OBJECTCONTEXT_H_

#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include <opencv/highgui.h>
#include <opencv2/features2d/features2d.hpp>

#include "ObjectType.h"
#include "POI.h"
#include "../Config.h"

namespace objpreproc {

/**
 * \class ObjectContext
 * @brief
 * @details
 * @date May 25, 2012
 * @author Gennaro Capo
 * @author Mirko Conte
 * @author Vincenzo De Notaris
 * @author Roberto Pacilio
 * @version 1.0
 * @namespace objpreproc
 */
template <class ObjectStrategy> class ObjectContext {

public:

	/**
	 * Costruttore della classe ObjectContext.
	 */
	inline ObjectContext() {
		_hsv = new cv::Mat(cv::Size(PROC_FRAME_WIDTH, PROC_FRAME_HEIGHT), CV_8UC3);
		_strategy = new ObjectStrategy;
	}

	/**
	 * Distruttore della classe ObjectContext.
	 */
	inline ~ObjectContext() {
		delete _strategy;
		delete _hsv;

		// Prevenzione del dangling reference.
		_strategy = NULL;
		_hsv = NULL;
	}

	/**
	 *
	 * @return
	 */
	inline const ObjectType getStrategyType() {
		return ObjectStrategy::getType();
	}

	/**
	 *
	 * @param src
	 * @return
	 */
	inline void doMask(const cv::Mat &src, cv::Mat &mask) {
		assert(!src.empty());

		cv::cvtColor(src, *_hsv, CV_BGR2HSV);
		_strategy->doThreshold(*_hsv, mask);
		_strategy->doErosion(mask, mask);
		_strategy->doDilatation(mask, mask);
	}


	inline void calcKeyPoints(const cv::Mat &image, std::vector<cv::KeyPoint> &keypoints, const cv::Mat &mask = cv::Mat()) {
		assert(!image.empty());

		_strategy->doBlobDetection(image, keypoints, mask);

	}

	inline void extractPOIs(const cv::Mat &depth, std::vector<cv::KeyPoint> &keypoints, std::vector<poi::POI*> &pois) {
		assert(!depth.empty());

		_strategy->doPOIExtraction(depth, keypoints, pois);
	}

private:

	/*
	 * Previene dalla costruzione mediante copia.
	 */
	ObjectContext(const ObjectContext&);

	/*
	 * Previene l'assegnamento.
	 */
	ObjectContext& operator = (const ObjectContext&);

	/*
	 * Strategia utilizzata per una data istanza della classe ObjectContext.
	 */
	ObjectStrategy* _strategy;

	cv::Mat* _hsv;

};

} /* namespace objpreproc */

#endif /* OBJECTCONTEXT_H_ */
